﻿using Microsoft.AspNetCore.Hosting;
using MongoDB.Driver;

namespace Luka.Log;

internal class MongoService : IMongoService
{
    // 定义一个只读的MongoClient对象
    private readonly MongoClient _client;

    // 定义一个只读的IMongoDatabase对象
    private readonly IMongoDatabase _database;

    // 定义一个静态的字符串变量_listName
    private readonly string _listName;

    public MongoService()
    {
        if (InternalApp.LogOptions != null)
        {
            // 获取MongoDB配置
            var mongo = InternalApp.LogOptions.Mongo;
            // 只创建一次 MongoClient 实例
            _client = new MongoClient(mongo.ConnectionString);
            // 根据环境变量选择数据库
            string db;
            // 判断是否在开发模式
            if (InternalApp.LogOptions.IsDev)
            {
                // 如果是开发模式，根据当前环境选择数据库
                db = InternalApp.HostEnvironment.IsDevelopment() ? !string.IsNullOrEmpty(mongo.DevDb) ? mongo.DevDb : $"{mongo.Db}_Dev" : mongo.Db;
            }
            else
            {
                // 非开发模式，优先使用 Db，若为空则使用 DevDb
                db = mongo.Db ?? mongo.DevDb;
            }
            // 如果数据库名称仍然为空，则设置默认值
            db ??= "Logging";
            // 根据PartitionEnum枚举值，将当前日期格式化为不同的字符串，并赋值给_db变量
            db = InternalApp.LogOptions.DbPart switch
            {
                // 如果PartitionEnum为Day，则将当前日期格式化为yyyyMMdd_的形式
                PartitionEnum.Day => $"{db}_{DateTime.Now:yyyyMMdd}",
                // 如果PartitionEnum为Month，则将当前日期格式化为yyyyMM_的形式
                PartitionEnum.Month => $"{db}_{DateTime.Now:yyyyMM}",
                // 如果PartitionEnum为Year，则将当前日期格式化为yyyy_的形式
                PartitionEnum.Year => $"{db}_{DateTime.Now:yyyy}",
                // 否则，直接赋值给_db变量
                _ => db
            };
            // 根据InternalApp.LogOptions.ListPart的值，设置_listName的值
            _listName = InternalApp.LogOptions.ListPart switch
            {
                // 如果ListPartitionEnum.Day，则_listName的值为当前日期的年月日
                PartitionEnum.Day => $"Log_{DateTime.Now:yyyyMMdd}",
                // 如果ListPartitionEnum.Month，则_listName的值为当前日期的年月
                PartitionEnum.Month => $"Log_{DateTime.Now:yyyyMM}",
                // 如果ListPartitionEnum.Year，则_listName的值为当前日期的年
                PartitionEnum.Year => $"Log_{DateTime.Now:yyyy}",
                // 默认情况下，_listName的值为Log
                _ => "Log"
            };
            // 获取数据库  _client为MongoDB的客户端实例，_db为数据库名称
            _database = _client.GetDatabase(db);
            // 如果过期时间大于0，则设置集合的过期时间
        }
    }

    /// <summary>
    ///  集合实例
    /// </summary>
    /// <returns></returns>
    public MongoClient Session() => _client;

    /// <summary>
    /// 单个数据库实例
    /// </summary>
    /// <returns></returns>
    public IMongoDatabase Db() => _database;

    /// <summary>
    /// 单个插入(自定义集合名称)
    /// </summary>
    /// <returns></returns>
    public async Task InsertOne(string collectionName, LoggingModel document)
    {
        // 获取指定集合
        var collection = Db().GetCollection<LoggingModel>(collectionName);
        // 创建索引
        CreateIndexModel(collection);
        // 插入文档
        await collection.InsertOneAsync(document);
    }

    /// <summary>
    /// 插入多个（自定义集合名称）
    /// </summary>
    public async Task InsertMany(string collectionName, IEnumerable<LoggingModel> documents)
    {
        // 获取指定集合
        var collection = Db().GetCollection<LoggingModel>(collectionName);
        // 创建索引
        CreateIndexModel(collection);
        // 异步插入多个文档
        await collection.InsertManyAsync(documents);
    }

    /// <summary>
    /// 单个插入(自定义集合名称)
    /// </summary>
    /// <returns></returns>
    public async Task InsertOne(LoggingModel document)
    {
        // 获取数据库中的集合
        var collection = Db().GetCollection<LoggingModel>(_listName);
        // 创建索引
        CreateIndexModel(collection);
        // 异步插入文档
        await collection.InsertOneAsync(document);
    }

    /// <summary>
    /// 插入多个（自定义集合名称）
    /// </summary>
    public async Task InsertMany(IEnumerable<LoggingModel> documents)
    {
        // 获取数据库中的集合
        var collection = Db().GetCollection<LoggingModel>(_listName);
        // 创建索引
        CreateIndexModel(collection);
        // 异步插入多个文档
        await collection.InsertManyAsync(documents);
    }

    /// <summary>
    /// 获取MongoDB集合
    /// </summary>
    /// <param name="name">集合名称</param>
    /// <returns></returns>
    public IMongoCollection<LoggingModel> GetCollection(string name)
    {
        return _database.GetCollection<LoggingModel>(name);
    }

    /// <summary>
    /// 创建索引
    /// </summary>
    /// <returns></returns>
    private void CreateIndexModel(IMongoCollection<LoggingModel> collection)
    {
        // 如果过期时间大于0，则设置集合的过期时间
        if (InternalApp.LogOptions.ExpireDays > 0)
        {
            // 定义索引键，按照LoggingModel中的Date字段升序排列
            var indexKeysDefinition = Builders<LoggingModel>.IndexKeys.Ascending(doc => doc.Date);
            // 定义索引选项，设置过期时间为days天
            var indexOptions = new CreateIndexOptions { ExpireAfter = TimeSpan.FromSeconds(60 * 60 * 24 * InternalApp.LogOptions.ExpireDays) };
            // 创建CreateIndexModel对象，传入索引键和索引选项
            var indexModel = new CreateIndexModel<LoggingModel>(indexKeysDefinition, indexOptions);
            collection.Indexes.CreateOne(indexModel);
        }
    }

    /// <summary>
    /// 释放上下文
    /// </summary>
    public void Dispose()
    {
        // 告诉垃圾回收器不再调用该对象的终结器
        GC.SuppressFinalize(this);
    }
}